package com.liu.activiti.listener;

import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.impl.util.CollectionUtil;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
public abstract class BaseActivitiExecutionListener implements ExecutionListener {

    @Resource
    public HistoryService historyService;

    @Resource
    public RepositoryService repositoryService;

    @Override
    public void notify(DelegateExecution execution) {
        switch (execution.getEventName()) {
            case EVENTNAME_START:
                if(isNomalStart(execution)){
                    log.info("触发工作流节点{}开始事件，执行正常start事件", execution);
                    doNormalStart(execution);
                } else {
                    log.info("触发工作流节点{}开始事件，执行回退事件", execution);
                    doNormalReback(execution);
                }
                break;
            case EVENTNAME_END:
                if(isNormalEnd(execution)){
                    log.info("触发工作流节点{}开始事件，执行正常end事件", execution);
                    doNormalEnd(execution);
                } else {
                    log.info("触发工作流节点{}开始事件，执行终止事件", execution);
                    doNormalTermination(execution);
                }
                break;
            default:
                log.info("未触发任何节点开始结束事件");
        }
    }

    protected  void doNormalTermination(DelegateExecution execution) {};

    protected void doNormalEnd(DelegateExecution execution) {};

    private boolean isNormalEnd(DelegateExecution execution) {
        //1.找到这个节点的上个触发节点是什么
        final HistoricActivityInstanceQuery historicActivityInstanceQuery =
                historyService.createHistoricActivityInstanceQuery();
        final List<HistoricActivityInstance> list = historicActivityInstanceQuery
                .processInstanceId(execution.getProcessInstanceId()).orderByHistoricActivityInstanceStartTime()
                .desc().list();
        //第一次执行流程
        if(CollectionUtil.isEmpty(list)) {
            return true;
        }
        final Optional<HistoricActivityInstance> lastNodeActivitiInstance = list.stream()
                .filter(act -> !act.getActivityId().equals(execution.getCurrentActivityId())).findFirst();
        if(!lastNodeActivitiInstance.isPresent()) {
            throw new RuntimeException("流程异常");
        }
        final HistoricActivityInstance historicActivityInstance = lastNodeActivitiInstance.get();
        final String currentActivityId = historicActivityInstance.getActivityId();

        //2.找到这个节点正常上个触发节点是什么
        BpmnModel bpmnModel = repositoryService.getBpmnModel(execution.getProcessDefinitionId());
        // 获取流程实例当前执行的节点
        org.activiti.bpmn.model.Process process = bpmnModel.getMainProcess();
        FlowElement currentFlowElement = process.getFlowElement(execution.getCurrentActivityId());
        // 遍历流程元素，寻找上一个节点
        if(!(currentFlowElement instanceof UserTask)) {
            return true;
        }
        UserTask currentUserTask = (UserTask) currentFlowElement;
        final List<String> flows = new ArrayList<>();
        final List<SequenceFlow> outgoingFlows = currentUserTask.getOutgoingFlows();
        for (SequenceFlow sequenceFlow: outgoingFlows) {
            if(sequenceFlow.getId().equals("newFlow")) {
                return false;
            }
        }
        return true;
    }

    protected  void doNormalReback(DelegateExecution execution) {};

    protected  void doNormalStart(DelegateExecution execution) {};

    private  boolean isNomalStart(DelegateExecution execution) {
        Object flag = execution.getVariable("nomalStartFlag");
        if(flag == null) {
            log.info("启动流程进入开始节点");
            return true;
        }
        final boolean nomalStartFlag = (boolean)execution.getVariable("nomalStartFlag");
        return nomalStartFlag;
    }
}

